home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / fs / inode.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  9KB  |  253 lines

  1. /* This file manages the inode table.  There are procedures to allocate and
  2.  * deallocate inodes, acquire, erase, and release them, and read and write
  3.  * them from the disk.
  4.  *
  5.  * The entry points into this file are
  6.  *   get_inode:       search inode table for a given inode; if not there, read it
  7.  *   put_inode:       indicate that an inode is no longer needed in memory
  8.  *   alloc_inode:  allocate a new, unused inode
  9.  *   wipe_inode:   erase some fields of a newly allocated inode
  10.  *   free_inode:   mark an inode as available for a new file
  11.  *   update_times: update atime, ctime, and mtime
  12.  *   rw_inode:       read a disk block and extract an inode, or corresp. write
  13.  *   dup_inode:       indicate that someone else is using an inode table entry
  14.  */
  15.  
  16. #include "fs.h"
  17. #include <sys/stat.h>
  18. #include <minix/boot.h>
  19. #include "buf.h"
  20. #include "file.h"
  21. #include "fproc.h"
  22. #include "inode.h"
  23. #include "super.h"
  24.  
  25. /*===========================================================================*
  26.  *                get_inode                     *
  27.  *===========================================================================*/
  28. PUBLIC struct inode *get_inode(dev, numb)
  29. dev_t dev;            /* device on which inode resides */
  30. ino_t numb;            /* inode number */
  31. {
  32. /* Find a slot in the inode table, load the specified inode into it, and
  33.  * return a pointer to the slot.  If 'dev' == NO_DEV, just return a free slot.
  34.  */
  35.  
  36.   register struct inode *rip, *xp;
  37.  
  38.   /* Search the inode table both for (dev, numb) and a free slot. */
  39.   xp = NIL_INODE;
  40.   for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) {
  41.     if (rip->i_count > 0) { /* only check used slots for (dev, numb) */
  42.         if (rip->i_dev == dev && rip->i_num == numb) {
  43.             /* This is the inode that we are looking for. */
  44.             rip->i_count++;
  45.             return(rip);    /* (dev, numb) found */
  46.         }
  47.     } else
  48.         xp = rip;    /* remember this free slot for later */
  49.   }
  50.  
  51.   /* Inode we want is not currently in use.  Did we find a free slot? */
  52.   if (xp == NIL_INODE) {    /* inode table completely full */
  53.     err_code = ENFILE;
  54.     return(NIL_INODE);
  55.   }
  56.  
  57.   /* A free inode slot has been located.  Load the inode into it. */
  58.   xp->i_dev = dev;
  59.   xp->i_num = numb;
  60.   xp->i_count = 1;
  61.   if (dev != NO_DEV) rw_inode(xp, READING);    /* get inode from disk */
  62.   xp->i_update = 0;        /* all the times are initially up-to-date */
  63.  
  64.   return(xp);
  65. }
  66.  
  67.  
  68. /*===========================================================================*
  69.  *                put_inode                     *
  70.  *===========================================================================*/
  71. PUBLIC void put_inode(rip)
  72. register struct inode *rip;    /* pointer to inode to be released */
  73. {
  74. /* The caller is no longer using this inode.  If no one else is using it either
  75.  * write it back to the disk immediately.  If it has no links, truncate it and
  76.  * return it to the pool of available inodes.
  77.  */
  78.  
  79.   if (rip == NIL_INODE) return;    /* checking here is easier than in caller */
  80.   if (--rip->i_count == 0) {    /* i_count == 0 means no one is using it now */
  81.     if ((rip->i_nlinks & BYTE) == 0) {
  82.         /* i_nlinks == 0 means free the inode. */
  83.         truncate(rip);    /* return all the disk blocks */
  84.         rip->i_mode = I_NOT_ALLOC;    /* clear I_TYPE field */
  85.         free_inode(rip->i_dev, rip->i_num);
  86.     }
  87.     else if (rip->i_pipe == I_PIPE) truncate(rip);
  88.     rip->i_pipe = NO_PIPE;  /* should always be cleared */
  89.  
  90.     if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
  91.   }
  92. }
  93.  
  94. /*===========================================================================*
  95.  *                alloc_inode                     *
  96.  *===========================================================================*/
  97. PUBLIC struct inode *alloc_inode(dev, bits)
  98. dev_t dev;            /* device on which to allocate the inode */
  99. mode_t bits;            /* mode of the inode */
  100. {
  101. /* Allocate a free inode on 'dev', and return a pointer to it. */
  102.  
  103.   register struct inode *rip;
  104.   register struct super_block *sp;
  105.   int major, minor;
  106.   ino_t numb;
  107.   bit_nr b;
  108.  
  109.   /* Acquire an inode from the bit map. */
  110.   sp = get_super(dev);        /* get pointer to super_block */
  111.   b=alloc_bit(sp->s_imap,(bit_nr)sp->s_ninodes+1, sp->s_imap_blocks,(bit_nr)0);
  112.   if (b == NO_BIT) {
  113.     err_code = ENFILE;
  114.     major = (int) (sp->s_dev >> MAJOR) & BYTE;
  115.     minor = (int) (sp->s_dev >> MINOR) & BYTE;
  116.     printf("Out of i-nodes on %sdevice %d/%d\n",
  117.         sp->s_dev == ROOT_DEV ? "root " : "", major, minor);
  118.     return(NIL_INODE);
  119.   }
  120.   numb = (ino_t) b;
  121.  
  122.   /* Try to acquire a slot in the inode table. */
  123.   if ( (rip = get_inode(NO_DEV, numb)) == NIL_INODE) {
  124.     /* No inode table slots available.  Free the inode just allocated. */
  125.     free_bit(sp->s_imap, b);
  126.   } else {
  127.     /* An inode slot is available. Put the inode just allocated into it. */
  128.     rip->i_mode = bits;
  129.     rip->i_nlinks = (nlink_t) 0;
  130.     rip->i_uid = fp->fp_effuid;
  131.     rip->i_gid = fp->fp_effgid;
  132.     rip->i_dev = dev;    /* was provisionally set to NO_DEV */
  133.  
  134.     /* Fields not cleared already are cleared in wipe_inode().  They have
  135.      * been put there because truncate() needs to clear the same fields if
  136.      * the file happens to be open while being truncated.  It saves space
  137.      * not to repeat the code twice.
  138.      */
  139.     wipe_inode(rip);
  140.   }
  141.  
  142.   return(rip);
  143. }
  144.  
  145. /*===========================================================================*
  146.  *                wipe_inode                     *
  147.  *===========================================================================*/
  148. PUBLIC void wipe_inode(rip)
  149. register struct inode *rip;    /* The inode to be erased. */
  150. {
  151. /* Erase some fields in the inode.  This function is called from alloc_inode()
  152.  * when a new inode is to be allocated, and from truncate(), when an existing
  153.  * inode is to be truncated.
  154.  */
  155.  
  156.   register int i;
  157.  
  158.   rip->i_size = 0;
  159.   rip->i_update = MTIME;    /* mark mtime for update later */
  160.   rip->i_dirt = DIRTY;
  161.   for (i = 0; i < NR_ZONE_NUMS; i++)
  162.     rip->i_zone[i] = NO_ZONE;
  163. }
  164.  
  165.  
  166. /*===========================================================================*
  167.  *                free_inode                     *
  168.  *===========================================================================*/
  169. PUBLIC void free_inode(dev, numb)
  170. dev_t dev;            /* on which device is the inode */
  171. ino_t numb;            /* number of inode to be freed */
  172. {
  173. /* Return an inode to the pool of unallocated inodes. */
  174.  
  175.   register struct super_block *sp;
  176.  
  177.   /* Locate the appropriate super_block. */
  178.   sp = get_super(dev);
  179.   free_bit(sp->s_imap, (bit_nr) numb);
  180. }
  181.  
  182. /*===========================================================================*
  183.  *                update_times                     *
  184.  *===========================================================================*/
  185. PUBLIC void update_times(rip)
  186. register struct inode *rip;    /* pointer to inode to be read/written */
  187. {
  188. /* Various system calls are required by the standard to update atime, ctime,
  189.  * or mtime.  Since updating a time requires sending a message to the clock
  190.  * task--an expensive business--the times are marked for update by setting
  191.  * bits in i_update.  When a stat, fstat, or sync is done, or an inode is 
  192.  * released, update_times() may be called to actually fill in the times
  193.  */
  194.  
  195.   time_t cur_time;
  196.  
  197.   cur_time = clock_time();
  198.   if (rip->i_update & ATIME) rip->i_atime = cur_time;
  199.   if (rip->i_update & CTIME) rip->i_ctime = cur_time;
  200.   if (rip->i_update & MTIME) rip->i_mtime = cur_time;
  201.   rip->i_update = 0;        /* they are all up-to-date now */
  202. }
  203.  
  204.  
  205. /*===========================================================================*
  206.  *                rw_inode                     *
  207.  *===========================================================================*/
  208. PUBLIC void rw_inode(rip, rw_flag)
  209. register struct inode *rip;    /* pointer to inode to be read/written */
  210. int rw_flag;            /* READING or WRITING */
  211. {
  212. /* An entry in the inode table is to be copied to or from the disk. */
  213.  
  214.   register struct buf *bp;
  215.   register d_inode *dip;
  216.   register struct super_block *sp;
  217.   block_nr b;
  218.  
  219.   /* Get the block where the inode resides. */
  220.   sp = get_super(rip->i_dev);
  221.   b = (block_nr) (rip->i_num - 1)/INODES_PER_BLOCK +
  222.                 sp->s_imap_blocks + sp->s_zmap_blocks + 2;
  223.   bp = get_block(rip->i_dev, b, NORMAL);
  224.   dip = bp->b_inode + (rip->i_num - 1) % INODES_PER_BLOCK;
  225.  
  226.   /* Do the read or write. */
  227.   if (rw_flag == READING) {
  228.     copy((char *)rip, (char *)dip, INODE_SIZE); /* copy to inode*/
  229.   } else {
  230.     if (rip->i_update) update_times(rip);    /* times need updating */
  231.     copy((char *)dip, (char *)rip, INODE_SIZE); /*